package com.softer.wxzj.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.softer.wxzj.common.entity.CommonResult;
import com.softer.wxzj.common.entity.Page;
import com.softer.wxzj.common.enums.MessageEnum;
import com.softer.wxzj.common.enums.NumStrEnum;
import com.softer.wxzj.common.enums.NumberEnum;
import com.softer.wxzj.common.enums.ShiroResultEnum;
import com.softer.wxzj.common.error.CourseException;
import com.softer.wxzj.common.json.JSONObject;
import com.softer.wxzj.common.util.*;
import com.softer.wxzj.common.websocket.websocket.WebSocketServer;
import com.softer.wxzj.entity.*;
import com.softer.wxzj.mapper.*;
import com.softer.wxzj.service.AccCalculateInterestInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zcz
 * @date 2019/7/5
 */
@Service
@Slf4j
public class AccCalculateInterestInfoServiceImpl implements AccCalculateInterestInfoService {

    @Autowired
    private AccCalculateInterestInfoMapper accCalculateInterestInfoMapper;
    @Autowired
    private AccRateInfoMapper accRateInfoMapper;
    @Autowired
    private BaseHouseInfoMapper baseHouseInfoMapper;
    @Autowired
    private AccTransactionLogMapper accTransactionLogMapper;
    @Autowired
    private AccCalculateInterestDetailLogMapper accCalculateInterestDetailLogMapper;
    @Autowired
    private AccCalculateInterestDetailMapper accCalculateInterestDetailMapper;
    @Autowired
    private AccInterestConfigMapper accInterestConfigMapper;
    @Autowired
    private BaseBankInfoMapper baseBankInfoMapper;
    @Autowired
    private BaseContractorBankInfoMapper baseContractorBankInfoMapper;
    /**
     * 本类实例 用于引用带事务的子方法
     */
    @Autowired
    private AccCalculateInterestInfoServiceImpl accCalculateInterestInfoServiceImpl;
    @Autowired
    private SysDicRateListMapper sysDicRateListMapper;
    @Autowired
    private BaseOwnerInfoMapper baseOwnerInfoMapper;
    @Autowired
    private SysCoreParamMapper sysCoreParamMapper;
    @Autowired
    private AccBusiVouchLinkMapper accBusiVouchLinkMapper;
    /**
     * 当前计算第几条  用于消息推送
     */
    public static int currentProgressCount;
    public static int totalCount;

    @Override
    public CommonResult insert(AccCalculateInterestInfo accCalculateInterestInfo) {
        return null;
    }

    @Override
    public CommonResult update(AccCalculateInterestInfo accCalculateInterestInfo) {
        int num = accCalculateInterestInfoMapper.update(accCalculateInterestInfo);
        return CommonResult.ResponseResult(num);
    }

    @Override
    public CommonResult delete(String id) {
        return null;
    }

    @Override
    public AccCalculateInterestInfo getInfo(String id) {
        return accCalculateInterestInfoMapper.getInfo(id);
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        if (NumStrEnum.ZERO.getNum().equals(accCalculateInterestInfo.getAccState()) && NumStrEnum.ONE.getNum().equals(accCalculateInterestInfo.getState())) {
            accCalculateInterestInfo.setAccState(null);
            accCalculateInterestInfo.setState(null);
        }
        Date now = DateFormatUtil.getDateFormat(DateUtils.getDateNow(), "yyyy-MM-dd");
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getList(accCalculateInterestInfo);
        list.forEach(ac -> {
            ac.setFullInterestDate(ac.getInterestYear() + "-" + ac.getInterestDate());
            //结息日期大于当前日期1    否则 0
            ac.setIsOperation(DateFormatUtil.getDateFormat(ac.getFullInterestDate(), "yyyy-MM-dd").before(now) ? NumStrEnum.ZERO.getNum() : NumStrEnum.ONE.getNum());
        });
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getRateDetailList(Page page, String id, String fuzzy) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getRateDetailList(id, fuzzy);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    @Transactional
    public CommonResult advanceInterest(String id) {
        AccCalculateInterestInfo accCalculateInterestInfo = accCalculateInterestInfoMapper.getInfo(id);
        //判断承办银行是否结算
        Map<String, String> map = checkContractorBankIsSettlement(accCalculateInterestInfo.getInterestYear() + "-" + accCalculateInterestInfo.getInterestDate());
        if (NumStrEnum.ZERO.getNum().equals(map.get("code"))) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), map.get("msg"));
        }
        //清空上次结息
        accCalculateInterestDetailMapper.deleteByRateNo(accCalculateInterestInfo.getRateNo());
        accCalculateInterestDetailLogMapper.deleteByRateNo(accCalculateInterestInfo.getRateNo());
        CommonResult commonResult = new CommonResult();
        //活期306  设置利率307  利息分配308  活期转定期309
        switch (accCalculateInterestInfo.getInterestType()) {
            case "306":
                commonResult = accCalculateInterestInfoServiceImpl.advanceInterestCurrent(accCalculateInterestInfo);
                break;
            case "307":
                commonResult = accCalculateInterestInfoServiceImpl.advanceInterestSetRate(accCalculateInterestInfo);
                break;
            case "308":
                commonResult = accCalculateInterestInfoServiceImpl.advanceInterestSetInterest(accCalculateInterestInfo);
                break;
            case "309":
                commonResult = accCalculateInterestInfoServiceImpl.advanceInterestFix(accCalculateInterestInfo);
                break;
        }
        return commonResult;
    }

    /**
     * 更新房屋
     *
     * @param houseId
     * @param accBal
     * @return
     */
    private int updateHouse(String houseId, BigDecimal accBal) {
        BaseHouseInfo baseHouseInfo = baseHouseInfoMapper.getInfo(houseId);
        BaseHouseInfo houseInfo = new BaseHouseInfo();
        houseInfo.setId(houseId);
        houseInfo.setAccrBal(baseHouseInfo.getAccrBal().add(accBal));
        return baseHouseInfoMapper.update(houseInfo);
    }

    //修改正在计算状态为 1是 0否
    @Override
    public int modifyIsCalculation(String id, String isCalculation) {
        return accCalculateInterestInfoMapper.updateIsCalculationById(isCalculation, id);
    }

    /**
     * 结息 确定结息，生成凭证写入财务
     *
     * @param id 结息记录id
     * @return
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult calculateInterest(String id) {
        //当前结息信息
        AccCalculateInterestInfo info = accCalculateInterestInfoMapper.getInfo(id);
        //判断承办银行是否结算
        Map<String, String> map = checkContractorBankIsSettlement(info.getInterestYear() + "-" + info.getInterestDate());
        if (NumStrEnum.ZERO.getNum().equals(map.get("code"))) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), map.get("msg"));
        }
        String rateDate = info.getInterestYear() + "-" + info.getInterestDate();
        Date tmpTallyDate = DateFormatUtil.getDateFormat(rateDate, "yyyy-MM-dd");
        //当前日期
        Date nowDate = DateFormatUtil.getDateFormat(DateUtils.getDateNow(), "yyyy-MM-dd");
        if (tmpTallyDate.after(nowDate)) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "未到结息日期！");
        }
        //预结息成功后 将预结息数据转为结息
        CommonResult result = accCalculateInterestInfoServiceImpl.advanceInterest(id);
        //预结息成功后 将预结息数据转为结息
        if (200 == result.getData()) {
            result = accCalculateInterestInfoServiceImpl.overaDvanceInterest(id, info, rateDate);
        }
        return result;
    }

    /**
     * 预结息转结息
     *
     * @param id
     * @param info
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult overaDvanceInterest(String id, AccCalculateInterestInfo info, String tallyDate) {
        currentProgressCount = NumberEnum.ZERO.getNum();
        //总利息
        BigDecimal totalInterest = BigDecimal.ZERO;
        //获取结息记录
        List<AccCalculateInterestDetail> accCalculateInterestDetails = accCalculateInterestDetailMapper.getCalcInterestDetails(id);
        //遍历每条结息信息
        totalCount = accCalculateInterestDetails.size();
        Date formatTallyDate = DateFormatUtil.getDateFormat(tallyDate, "yyyy-MM-dd");
        for (AccCalculateInterestDetail accCalculateInterestDetail : accCalculateInterestDetails) {
            totalInterest = totalInterest.add(accCalculateInterestDetail.getInterestAmount());
            currentProgressCount++;
            sendWebSocket(totalCount, currentProgressCount, "正在记账并写入财务..");
            String tmpHouseId = accCalculateInterestDetail.getHouseId();
            BigDecimal tmpInterestAmount = accCalculateInterestDetail.getInterestAmount();
            //查询大于结息日期的最大的交易记录
            AccTransactionLog transactionLog = accCalculateInterestDetailLogMapper.getTransLogByHouseIdAndTallyDate(tmpHouseId, tallyDate);
            int num = saveAccTransactionLog(accCalculateInterestDetail, transactionLog, info);
            // 修改房间信息的利息及计息日期
            accTransactionLogMapper.updateHouseInfoRateDate(tmpInterestAmount, (new SimpleDateFormat("yyyy-MM-dd")).format(formatTallyDate), tmpHouseId);
            if (num == NumberEnum.ZERO.getNum()) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
            }
        }
        //修改结息信息为结束状态
        int num = accCalculateInterestInfoMapper.overAccCalculateInterestInfo(totalInterest, id);
        if (num == NumberEnum.ZERO.getNum()) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        //财务接口
        sendFinance(info.getRateNo());
        //插入新的结息记录
        AccInterestConfig config = getNextAccInterestConfig(tallyDate);
        if (null != config) {
            num = accCalculateInterestInfoServiceImpl.saveAccCalculateInterestInfo(config);
            if (num == NumberEnum.ZERO.getNum()) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
            }
        }
        return CommonResult.ResponseResult(NumberEnum.ONE.getNum());
    }

    /**
     * 保存交易信息表
     *
     * @param accCalculateInterestDetail
     * @param transactionLog
     * @param info
     * @return
     */
    private int saveAccTransactionLog(AccCalculateInterestDetail accCalculateInterestDetail, AccTransactionLog transactionLog, AccCalculateInterestInfo info) {
        String tmpHouseId = accCalculateInterestDetail.getHouseId();
        BigDecimal tmpInterestAmount = accCalculateInterestDetail.getInterestAmount();
        String tmpRateNo = accCalculateInterestDetail.getRateNo();
        String rateDate = info.getInterestYear() + "-" + info.getInterestDate();
        AccTransactionLog accTransactionLog = new AccTransactionLog();
        accTransactionLog.setHouseId(tmpHouseId);
        accTransactionLog.setBusiNo(tmpRateNo);
        accTransactionLog.setBusiType("313");
        accTransactionLog.setState(NumStrEnum.ONE.getNum());
        accTransactionLog.setTallyDate(rateDate);
        accTransactionLog.setPayAmount(tmpInterestAmount);
        BaseOwnerInfo infoByAccNo = baseOwnerInfoMapper.getInfoByAccNo(tmpHouseId);
        if (null != infoByAccNo) {
            accTransactionLog.setOwnerId(infoByAccNo.getId());
        }
        BaseHouseInfo houseInfo = baseHouseInfoMapper.getInfo(tmpHouseId);
        accTransactionLog.setAccrBal(tmpInterestAmount);
        //BigDecimal logFundBal = BigDecimal.ZERO;
        //BigDecimal logAccrBal = BigDecimal.ZERO;
        if (null != transactionLog) {
            //transactionLog.getFundBal() = null == houseInfo.getFundBal() ? BigDecimal.ZERO : houseInfo.getFundBal();
            //logAccrBal = null == houseInfo.getAccrBal() ? BigDecimal.ZERO : houseInfo.getAccrBal();
            accTransactionLog.setBankId(houseInfo.getBankId());
        }
        accTransactionLog.setFundBal(transactionLog.getFundBal());
        accTransactionLog.setAccountType("325");
        accTransactionLog.setIoFlag("In");
        accTransactionLog.setBankId(accCalculateInterestDetail.getBankId());
        //插入记录
        return accTransactionLogMapper.insert(accTransactionLog);
    }

    /**
     * 预结息转成结息
     *
     * @param id
     * @return
     */
    @Override
    @Transactional
    public CommonResult accordAdvanceInterest(String id) {
        //修改是否处于结息中为是
        //modifyIsCalculation(id,NumStrEnum.ONE.getNum());
        //当前结息信息
        AccCalculateInterestInfo info = accCalculateInterestInfoMapper.getInfo(id);
        //判断承办银行是否结算
        Map<String, String> map = checkContractorBankIsSettlement(info.getInterestYear() + "-" + info.getInterestDate());
        if (NumStrEnum.ZERO.getNum().equals(map.get("code"))) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), map.get("msg"));
        }
        String rateDate = info.getInterestYear() + "-" + info.getInterestDate();
        Date tmpTallyDate = DateFormatUtil.getDateFormat(rateDate, "yyyy-MM-dd");
        //当前日期
        Date nowDate = DateFormatUtil.getDateFormat(DateUtils.getDateNow(), "yyyy-MM-dd");
        if (tmpTallyDate.after(nowDate)) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "未到结息日期！");
        }
        return overaDvanceInterest(id, info, rateDate);
    }

    @Override
    public String getIsAdvanceById(String id) {
        return accCalculateInterestInfoMapper.getIsAdvanceById(id);
    }

    /**
     * 获取下一个结息节点
     *
     * @param fullInterestDate
     * @return
     */
    private AccInterestConfig getNextAccInterestConfig(String fullInterestDate) {
        List<AccInterestConfig> list = accInterestConfigMapper.getList();
        String interestYear = StringUtils.substring(String.valueOf(fullInterestDate), 0, 4);
        list.forEach(a -> a.setFullInterestDate(DateFormatUtil.getDateFormat(interestYear + "-" + a.getInterestDate(), "yyyy-MM-dd")));
        List<AccInterestConfig> collect = list.stream().filter(a -> a.getFullInterestDate().after(DateFormatUtil.getDateFormat(fullInterestDate, "yyyy-MM-dd"))).collect(Collectors.toList());
        if (null != collect && collect.size() > 0) {
            collect.get(0).setInterestYear(interestYear);
            return collect.get(0);
        } else {
            list.forEach(a -> a.setFullInterestDate(DateFormatUtil.getDateFormat((Integer.parseInt(interestYear) + 1) + "-" + a.getInterestDate(), "yyyy-MM-dd")));
            list.get(0).setInterestYear(String.valueOf((Integer.parseInt(interestYear) + 1)));
            return list.get(0);
        }
    }

    //插入新的结息记录
    @Transactional
    public int saveAccCalculateInterestInfo(AccInterestConfig accInterestConfig) {
        AccCalculateInterestInfo accCalculateInterestInfo = new AccCalculateInterestInfo();
        accCalculateInterestInfo.setId(UUIDUtil.getUUID());
        accCalculateInterestInfo.setRateNo(NumGeneratorUtil.getLongNo(NumStrEnum.ONE.getNum()));
        accCalculateInterestInfo.setAccountType(accInterestConfig.getAccountType());
        accCalculateInterestInfo.setInterestYear(accInterestConfig.getInterestYear());
        accCalculateInterestInfo.setInterestDate(accInterestConfig.getInterestDate());
        accCalculateInterestInfo.setInterestType(accInterestConfig.getInterestType());
        accCalculateInterestInfo.setCreater(ShiroUserUtil.getUserName());
        accCalculateInterestInfo.setState(NumStrEnum.ONE.getNum());
        accCalculateInterestInfo.setAccState(NumStrEnum.ZERO.getNum());
        //活期赋值利率类型为1活期（定期自选利率类型，设置利率、利息分配无利率类型）
        if ("306".equals(accCalculateInterestInfo.getInterestType())) {
            accCalculateInterestInfo.setRateType(NumStrEnum.ONE.getNum());
        }
        return accCalculateInterestInfoMapper.insert(accCalculateInterestInfo);
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getInterestRegionList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getInterestRegionList(accCalculateInterestInfo);
        if (null == list || 0 == list.size()) {
            return new PageInfo<>(list);
        }
        //总合计
        AccCalculateInterestInfo total = accCalculateInterestInfoMapper.getInterestRegionTotal(accCalculateInterestInfo);
        //赋值合计
        setList(list, total);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getInterestBuildList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getInterestBuildList(accCalculateInterestInfo);
        if (null == list || 0 == list.size()) {
            return new PageInfo<>(list);
        }
        //总合计
        AccCalculateInterestInfo total = accCalculateInterestInfoMapper.getInterestBuildTotal(accCalculateInterestInfo);
        //赋值合计
        setList(list, total);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }


    @Override
    public PageInfo<AccCalculateInterestInfo> getInterestHouseList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getInterestHouseList(accCalculateInterestInfo);
        if (null == list || 0 == list.size()) {
            return new PageInfo<>(list);
        }
        //总合计
        AccCalculateInterestInfo total = accCalculateInterestInfoMapper.getInterestHouseTotal(accCalculateInterestInfo);
        //赋值合计
        setList(list, total);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    /**
     * 给list赋值本页合计  总合计
     *
     * @param list
     * @param total
     */
    private void setList(List<AccCalculateInterestInfo> list, AccCalculateInterestInfo total) {
        //原始集合
        List<AccCalculateInterestInfo> originalList = new ArrayList<>();
        //todo 收益分配模块还没做  暂时定义收益分配变量
        list.forEach(l -> l.setDistributionAmount(l.getDistributionAmount() == null ? BigDecimal.ZERO : l.getDistributionAmount()));
        list.forEach(l -> l.setTotalAmount(l.getInterestAmount().add(l.getDistributionAmount())));
        originalList.addAll(list);
        list.add(setPageTotalList(originalList));
        list.add(setTotalList(total));
    }

    /**
     * 计算总合计
     *
     * @param total
     * @return
     */
    private AccCalculateInterestInfo setTotalList(AccCalculateInterestInfo total) {
        //所有的总计
        if (null == total) {
            total = new AccCalculateInterestInfo();
            total.setInterestAmount(BigDecimal.ZERO);
            total.setDistributionAmount(BigDecimal.ZERO);
            total.setTotalAmount(BigDecimal.ZERO);
        } else {
            //todo 暂时定义收益分配为0
            total.setDistributionAmount(BigDecimal.ZERO);
            total.setTotalAmount(total.getInterestAmount().add(total.getDistributionAmount()));
        }
        return total;
    }

    /**
     * 计算本页合计
     *
     * @param list
     * @return
     */
    private AccCalculateInterestInfo setPageTotalList(List<AccCalculateInterestInfo> list) {
        //本页总计
        AccCalculateInterestInfo pageTotal = new AccCalculateInterestInfo();
        BigDecimal interestAmount = BigDecimal.ZERO;
        BigDecimal distributionAmount = BigDecimal.ZERO;
        BigDecimal totalAmount;
        for (AccCalculateInterestInfo calculateInterestInfo : list) {
            //TODO 收益分配暂未开发
            //totalDistributionAmount = totalDistributionAmount.add(calculateInterestInfo.getDistributionAmount());
            interestAmount = interestAmount.add(calculateInterestInfo.getInterestAmount());
        }
        totalAmount = interestAmount.add(distributionAmount);
        pageTotal.setInterestAmount(interestAmount);
        pageTotal.setDistributionAmount(distributionAmount);
        pageTotal.setTotalAmount(totalAmount);
        return pageTotal;
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getInterestHouseDetailList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getInterestHouseDetailList(accCalculateInterestInfo);
        if (null == list || 0 == list.size()) {
            return new PageInfo<>(list);
        }
        //收益分配没做  暂时全部设为业主利息
        list.forEach(a -> a.setTransTypeName("业主利息"));
        //本页合计
        AccCalculateInterestInfo pageTotal = new AccCalculateInterestInfo();
        //总合计
        AccCalculateInterestInfo total;
        total = accCalculateInterestInfoMapper.getInterestHouseDetailTotal(accCalculateInterestInfo);
        if (null == total) {
            total = new AccCalculateInterestInfo();
        }
        BigDecimal interestAmount = BigDecimal.ZERO;
        for (AccCalculateInterestInfo calculateInterestInfo : list) {
            interestAmount = interestAmount.add(calculateInterestInfo.getInterestAmount());
        }
        pageTotal.setInterestAmount(interestAmount);
        list.add(pageTotal);
        list.add(total);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getInventoryRegionList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getInventoryRegionList(accCalculateInterestInfo);
        BigDecimal interestAmount = BigDecimal.ZERO;
        BigDecimal funBal = BigDecimal.ZERO;
        for (AccCalculateInterestInfo a : list) {
            //结息金额
            interestAmount = interestAmount.add(a.getInterestAmount());
            //账户金额
            funBal = funBal.add(a.getFundBal());
        }
        //本页金额
        AccCalculateInterestInfo a = new AccCalculateInterestInfo();
        //两位小数
        round(funBal, interestAmount, a);
        list.add(a);
        //总金额
        AccCalculateInterestInfo amountAll = new AccCalculateInterestInfo();
        amountAll.setInterestAmount(accCalculateInterestInfoMapper.getInventoryRegionListAll(accCalculateInterestInfo).getInterestAmount());
        amountAll.setFundBal(accCalculateInterestInfoMapper.getInventoryRegionListAll(accCalculateInterestInfo).getFundBal());
        list.add(amountAll);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    private AccCalculateInterestInfo round(BigDecimal funBal, BigDecimal interestAmount, AccCalculateInterestInfo a) {
        //两位小数
        DecimalFormat df = new DecimalFormat("#.00");
        BigDecimal f;
        BigDecimal interes;
        if (funBal != null) {
            f = new BigDecimal(df.format(funBal));
            a.setFundBal(f);
        } else {
            a.setFundBal(funBal);
        }
        if (interestAmount != null) {
            interes = new BigDecimal(df.format(interestAmount));
            a.setInterestAmount(interes);
        } else {
            a.setInterestAmount(interestAmount);
        }
        return a;
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getInventoryBuildList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getInventoryBuildList(accCalculateInterestInfo);
        BigDecimal interestAmount = BigDecimal.ZERO;
        BigDecimal funBal = BigDecimal.ZERO;
        for (AccCalculateInterestInfo a : list) {
            //结息金额
            interestAmount = interestAmount.add(a.getInterestAmount());
            //账户金额
            funBal = funBal.add(a.getFundBal());
        }
        AccCalculateInterestInfo pageMoney = new AccCalculateInterestInfo();
        //两位小数
        round(funBal, interestAmount, pageMoney);
        list.add(pageMoney);
        //总金额
        AccCalculateInterestInfo allMoney = accCalculateInterestInfoMapper.getInventoryBuildListAll(accCalculateInterestInfo);
        list.add(allMoney);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<AccCalculateInterestInfo> getInventoryHouseList(Page page, AccCalculateInterestInfo accCalculateInterestInfo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AccCalculateInterestInfo> list = accCalculateInterestInfoMapper.getInventoryHouseList(accCalculateInterestInfo);
        BigDecimal interestAmount = BigDecimal.ZERO;
        BigDecimal funBal = BigDecimal.ZERO;
        for (AccCalculateInterestInfo a : list) {
            //结息金额
            interestAmount = interestAmount.add(a.getInterestAmount());
            //账户金额
            funBal = funBal.add(a.getFundBal());
        }
        AccCalculateInterestInfo pageMoney = new AccCalculateInterestInfo();
        round(funBal, interestAmount, pageMoney);
        list.add(pageMoney);
        AccCalculateInterestInfo allMoney = accCalculateInterestInfoMapper.getInventoryHouseListAll(accCalculateInterestInfo);
        allMoney.setInterestAmount(allMoney.getInterestAmount().setScale(4, BigDecimal.ROUND_HALF_UP));
        allMoney.setFundBal(allMoney.getFundBal().setScale(4, BigDecimal.ROUND_HALF_UP));
        list.add(allMoney);
        PageInfo<AccCalculateInterestInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }


    /**
     * 设置利率预结息
     *
     * @param accCalculateInterestInfo
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult advanceInterestSetRate(AccCalculateInterestInfo accCalculateInterestInfo) {
        currentProgressCount = 0;
        //判断是否设置利率
        if (null == accCalculateInterestInfo.getRate()) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "请先设置利率");
        }
        //当前结息日期
        String currentDate = accCalculateInterestInfo.getInterestYear() + "-" + accCalculateInterestInfo.getInterestDate();
        //查询最后一次已结息记录
        AccCalculateInterestInfo lastCalculationInfo = accCalculateInterestInfoMapper.getLastCalculationInfo();
        //上次结息日期   没有则赋值最小的缴存记账日期 表示系统第一次结息
        String lastDate = null != lastCalculationInfo ? lastCalculationInfo.getInterestYear() + "-" + lastCalculationInfo.getInterestDate() : getMinDepTallyDate(currentDate);
        Date currentDateFormat = DateFormatUtil.getDateFormat(currentDate, "yyyy-MM-dd");
        //Date lastDateFormat = DateFormatUtil.getDateFormat(lastDate, "yyyy-MM-dd");
        //查询有当前资金余额的房屋的id、资金余额、利息、承办银行列表
        List<BaseHouseInfo> houseList = baseHouseInfoMapper.getHouseListToInterest(currentDate);
        if (null == houseList || houseList.isEmpty()) {
            //更新结息表状态
            int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, BigDecimal.ZERO);

            return CommonResult.ResponseResult(num);
        }
        //所有房间的总利息
        BigDecimal totalInterest = BigDecimal.ZERO;
        totalCount = houseList.size();
        for (BaseHouseInfo baseHouseInfo : houseList) {
            currentProgressCount++;
            sendWebSocket(totalCount, currentProgressCount, "正在结息..");
            //单个房间的总利息
            BigDecimal houseTotalInterest = BigDecimal.ZERO;
            //查询房屋的所有记账记录
            List<AccCalculateInterestDetailLog> accCalculateInterestDetailLogList = accCalculateInterestDetailLogMapper.getLogListByHouseIdAndLastDate(baseHouseInfo.getId(), lastDate);
            //遍历每段业务计算利息
            String detailId = UUIDUtil.getUUID();
            for (int i = 0; i < accCalculateInterestDetailLogList.size(); i++) {
                Date startDate = DateFormatUtil.getDateFormat(accCalculateInterestDetailLogList.get(i).getTallyDate(), "yyyy-MM-dd");
                Date endDate = null;
                //分段计息天数
                if (i < accCalculateInterestDetailLogList.size() - 1) {
                    endDate = DateFormatUtil.getDateFormat(accCalculateInterestDetailLogList.get(i + 1).getTallyDate(), "yyyy-MM-dd");
                } else {
                    endDate = currentDateFormat;
                }
                int dayNumber = DateFormatUtil.getDiscrepantDays(startDate, endDate);
                //计算利息
                BigDecimal dFundbal = accCalculateInterestDetailLogList.get(i).getFundBal();//本金
                BigDecimal dAccrBal = accCalculateInterestDetailLogList.get(i).getAccrBal();//利息
                BigDecimal fundbal = null == dFundbal ? BigDecimal.ZERO : dFundbal;
                BigDecimal accrBal = null == dAccrBal ? BigDecimal.ZERO : dAccrBal;
                BigDecimal totalBal = fundbal.add(accrBal);
                BigDecimal dRate = accCalculateInterestInfo.getRate().divide(new BigDecimal(36000), 12, BigDecimal.ROUND_HALF_UP);//利率 / 100 /360
                BigDecimal interestAmount = totalBal.multiply(dRate).multiply(new BigDecimal(dayNumber));
                interestAmount = interestAmount.setScale(4, BigDecimal.ROUND_DOWN);
                houseTotalInterest = houseTotalInterest.add(interestAmount);
                accCalculateInterestDetailLogList.get(i).setDetailId(detailId);
                //保存分段计息详情表
                saveAccCalculateInterestDetailLog(accCalculateInterestDetailLogList.get(i), dayNumber, interestAmount, String.valueOf(accCalculateInterestInfo.getRate()), accCalculateInterestInfo.getRateNo(), startDate, endDate);
            }
            totalInterest = totalInterest.add(houseTotalInterest);
            //保存结息详情表
            saveAccCalculateInterestDetail(baseHouseInfo, houseTotalInterest, accCalculateInterestInfo.getRateNo(), detailId, accCalculateInterestInfo);
        }
        //更新结息表状态
        int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, totalInterest);
        return CommonResult.ResponseResult(num);
    }

    /**
     * 活期预结息
     *
     * @param accCalculateInterestInfo 当前在用结息信息记录
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult advanceInterestCurrent(AccCalculateInterestInfo accCalculateInterestInfo) {
        currentProgressCount = 0;
        //当前结息日期
        String currentDate = accCalculateInterestInfo.getInterestYear() + "-" + accCalculateInterestInfo.getInterestDate();
        //查询最后一次已结息记录
        AccCalculateInterestInfo lastCalculationInfo = accCalculateInterestInfoMapper.getLastCalculationInfo();
        //上次结息日期   没有则赋值小于等于当前结息日期的最小的缴存记账日期 表示系统第一次结息
        String lastDate = null != lastCalculationInfo ? lastCalculationInfo.getInterestYear() + "-" + lastCalculationInfo.getInterestDate() : getMinDepTallyDate(currentDate);
        Date currentDateFormat = DateFormatUtil.getDateFormat(currentDate, "yyyy-MM-dd");
        //查询房屋绑定过的承办银行（1，2，3，... ...）
        String bankIdList = baseHouseInfoMapper.getBankIdListToInterest();
        //取当前结息信息中的 利率类型  rate_Type  1 活期  2 3 4 ... ...
        //根据结息类型和结息区间查询利率列表  最近结息时间>=利息开始时间  && 利息结束时间>=当前结息日期
        List<AccRateInfo> rateInfoList = accRateInfoMapper.getListByDateAndRateType(currentDate, lastDate, bankIdList, NumStrEnum.ONE.getNum());
        //检查是否所有银行都存在设置利率且日期是否连续
        String[] arrBankId = bankIdList.split(",");
        for (String sBankId : arrBankId) {
            List<AccRateInfo> tmpRateInfoList = rateInfoList.stream().filter((AccRateInfo accRateinfo) -> accRateinfo.getBankId().compareTo(sBankId) == 0).collect(Collectors.toList());
            BaseBankInfo bankInfo = baseBankInfoMapper.getInfo(sBankId);
            if (null == tmpRateInfoList || tmpRateInfoList.isEmpty()) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), bankInfo.getBankName() + "活期利率未配置利率或利率不完整！");
            }
            //检查利率日期是否完整
            if (!checkRateDate(tmpRateInfoList)) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), bankInfo.getBankName() + "活期利率日期不完整！");
            }
        }
        //查询有当前资金余额并且最小有效的缴存记账日期>当前结息日期的房屋列表
        List<BaseHouseInfo> houseList = baseHouseInfoMapper.getHouseListToInterest(currentDate);
        if (null == houseList || houseList.isEmpty()) {
            //更新结息表状态
            int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, BigDecimal.ZERO);
            return CommonResult.ResponseResult(num);
        }
        //所有房间的总利息
        BigDecimal totalInterest = BigDecimal.ZERO;
        totalCount = houseList.size();
        //遍历可结息房间列表
        for (BaseHouseInfo baseHouseInfo : houseList) {
            currentProgressCount++;
            sendWebSocket(totalCount, currentProgressCount, "正在结息..");
            //单个房间的总利息
            BigDecimal houseTotalInterest;
            //获取房间对应承办银行的利率列表,分利息节点计息（单银行会有多个利率时间节点）
            List<AccRateInfo> currentRateInfoList = rateInfoList.stream().filter((AccRateInfo accRateinfo) -> accRateinfo.getBankId().equals(baseHouseInfo.getBankCode())).collect(Collectors.toList());
            //详情表id
            String detailId = UUIDUtil.getUUID();
            houseTotalInterest = getHouseTotalInterest(currentRateInfoList, currentDateFormat, baseHouseInfo, lastDate, currentDate, accCalculateInterestInfo.getRateNo(), detailId, BigDecimal.ZERO);
            //加总利息
            totalInterest = totalInterest.add(houseTotalInterest);
            //保存结息详情表
            saveAccCalculateInterestDetail(baseHouseInfo, houseTotalInterest, accCalculateInterestInfo.getRateNo(), detailId, accCalculateInterestInfo);
        }
        //更新结息表状态
        int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, totalInterest);
        return CommonResult.ResponseResult(num);
    }


    /**
     * 活期计息  按交易记录明细及利率节点计算一个房间的利息，保存分段利息
     *
     * @param rateInfoList      对应银行的利息列表
     * @param currentDateFormat 结束计息期
     * @param baseHouseInfo     房屋帐户信息
     * @param lastAmount        上次结息资金余额  活期传0  活转定传对应金额   主要用在活转定时计算新交存的活期利息
     * @return 一个房间的利息金额
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public BigDecimal getHouseTotalInterest(List<AccRateInfo> rateInfoList, Date currentDateFormat, BaseHouseInfo baseHouseInfo, String lastDate, String currentDate, String rateNo, String detailId, BigDecimal lastAmount) {
        //单个房间的总利息
        BigDecimal houseTotalInterest = BigDecimal.ZERO;
        //查询房屋的记账记录列表   记账日期>=最近结息日期  &&  记账日期<当前日期结息
        List<AccCalculateInterestDetailLog> accCalculateInterestDetailLogList = accCalculateInterestDetailLogMapper.getLogListByHouseIdAndDateInterval(baseHouseInfo.getId(), lastDate, currentDate);
        //遍历最终的分段计息集合
        for (int i = 0; i < accCalculateInterestDetailLogList.size(); i++) {
            List<AccRateInfo> rateList;
            //本次交易记录所适用的开始及结束日期
            Date tmpStartDate = DateFormatUtil.getDateFormat(accCalculateInterestDetailLogList.get(i).getTallyDate(), "yyyy-MM-dd");
            Date tmpEndDate;
            //判断是否不为最后一条计息记录
            if (i < accCalculateInterestDetailLogList.size() - 1) {
                tmpEndDate = DateFormatUtil.getDateFormat(accCalculateInterestDetailLogList.get(i + 1).getTallyDate(), "yyyy-MM-dd");
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(tmpEndDate);
                //calendar.add(Calendar.DATE, -1);
                //结束日期前一天
                Date tmpEndDateSubtractOne = calendar.getTime();
                tmpEndDate = tmpEndDateSubtractOne;
                //过滤记账日期节点中包含的利率配置列表  利率开始日期 > 下一笔记账的日期 && 利率结束日期 > 本次记账日期
                rateList = rateInfoList.stream().filter(rateInfo -> (DateFormatUtil.getDateFormat(rateInfo.getStartDate(), "yyyy-MM-dd").before(tmpEndDateSubtractOne) && !DateFormatUtil.getDateFormat(rateInfo.getEndDate(), "yyyy-MM-dd").before(tmpStartDate))).collect(Collectors.toList());
            } else {
                tmpEndDate = currentDateFormat;
                //过滤记账日期节点中包含的利率配置列表  利率开始日期 > 当前结息日期 && 利率结束日期 > 本次记账日期
                rateList = rateInfoList.stream().filter(rateInfo -> (DateFormatUtil.getDateFormat(rateInfo.getStartDate(), "yyyy-MM-dd").before(currentDateFormat) && !DateFormatUtil.getDateFormat(rateInfo.getEndDate(), "yyyy-MM-dd").before(tmpStartDate))).collect(Collectors.toList());
            }

            //修改本时间段的起始和结束日期
            AccRateInfo tmpAccRateInfo = new AccRateInfo();
            tmpAccRateInfo.setEndDate(rateList.get(0).getEndDate());
            tmpAccRateInfo.setRate(rateList.get(0).getRate());
            tmpAccRateInfo.setRateType(rateList.get(0).getRateType());
            tmpAccRateInfo.setStartDate((new SimpleDateFormat("yyyy-MM-dd")).format(tmpStartDate));
            rateList.set(0, tmpAccRateInfo);
            AccRateInfo tmpAccRateInfo1 = new AccRateInfo();
            tmpAccRateInfo1.setStartDate(rateList.get(rateList.size() - 1).getStartDate());
            tmpAccRateInfo1.setRate(rateList.get(rateList.size() - 1).getRate());
            tmpAccRateInfo1.setRateType(rateList.get(rateList.size() - 1).getRateType());
            tmpAccRateInfo1.setEndDate((new SimpleDateFormat("yyyy-MM-dd")).format(tmpEndDate));
            rateList.set(rateList.size() - 1, tmpAccRateInfo1);
            for (int j = 0; j < rateList.size(); j++) {
                //分段计息天数
                Date tmpSDate = DateFormatUtil.getDateFormat(rateList.get(j).getStartDate(), "yyyy-MM-dd");
                Date tmpEDate = DateFormatUtil.getDateFormat(rateList.get(j).getEndDate(), "yyyy-MM-dd");
                //分段计息天数=本次利率结束日期-本次利率开始日期
                int dayNumber = DateFormatUtil.getDiscrepantDays(tmpSDate, tmpEDate);
                //本金 + 利息
                BigDecimal dFundbal = accCalculateInterestDetailLogList.get(i).getFundBal().add(accCalculateInterestDetailLogList.get(i).getAccrBal());
                BigDecimal amount = null == lastAmount ? BigDecimal.ZERO : lastAmount;
                //实际计算金额 = 本金 + 利息 - 新交存金额（仅活期转定期 计算新交存利息时有值，其他为0）
                BigDecimal subtract = dFundbal.subtract(amount);
                //日lilv = 当前利率 / 360 /100
                BigDecimal dRate = rateList.get(j).getRate().divide(new BigDecimal(36000), 12, BigDecimal.ROUND_HALF_UP);//利率 / 100 /360
                BigDecimal interestAmount = subtract.multiply(dRate).multiply(new BigDecimal(dayNumber));
                interestAmount = interestAmount.setScale(4, BigDecimal.ROUND_DOWN);
                houseTotalInterest = houseTotalInterest.add(interestAmount);
                accCalculateInterestDetailLogList.get(i).setDetailId(detailId);
                //赋值实际计算的金额
                accCalculateInterestDetailLogList.get(i).setFundBal(subtract);
                //保存分段计息详情表
                saveAccCalculateInterestDetailLog(accCalculateInterestDetailLogList.get(i), dayNumber, interestAmount, String.valueOf(rateList.get(j).getRate()), rateNo, DateFormatUtil.getDateFormat(rateList.get(j).getStartDate(), "yyyy-MM-dd"), DateFormatUtil.getDateFormat(rateList.get(j).getEndDate(), "yyyy-MM-dd"));
            }
        }
        return houseTotalInterest;
    }

    /**
     * 新增结息节点记录详情表
     *
     * @param accCalculateInterestDetailLog
     * @param dayNumber
     * @param interestAmount
     * @return
     */
    private int saveAccCalculateInterestDetailLog(AccCalculateInterestDetailLog accCalculateInterestDetailLog, int dayNumber, BigDecimal interestAmount, String rate, String rateNo, Date startDate, Date endDate) {
        accCalculateInterestDetailLog.setId(UUIDUtil.getUUID());
        accCalculateInterestDetailLog.setInterestAmount(interestAmount);
        accCalculateInterestDetailLog.setDayNumber(dayNumber);
        accCalculateInterestDetailLog.setRateNo(rateNo);
        accCalculateInterestDetailLog.setRate(rate);
        accCalculateInterestDetailLog.setInterestStartDate(startDate);
        accCalculateInterestDetailLog.setInterestEndDate(endDate);
        return accCalculateInterestDetailLogMapper.insert(accCalculateInterestDetailLog);
    }

    /**
     * 新增结息记录详情表
     *
     * @param baseHouseInfo
     * @param houseInterestAmount
     * @param rateNo
     * @return
     */
    private int saveAccCalculateInterestDetail(BaseHouseInfo baseHouseInfo, BigDecimal houseInterestAmount, String rateNo, String uuid, AccCalculateInterestInfo accCalculateInterestInfo) {
        AccCalculateInterestDetail accCalculateInterestDetail = new AccCalculateInterestDetail();
        accCalculateInterestDetail.setCreater(ShiroUserUtil.getUserName());
        accCalculateInterestDetail.setId(uuid);
        accCalculateInterestDetail.setBankId(baseHouseInfo.getBankCode());
        accCalculateInterestDetail.setHouseId(baseHouseInfo.getId());
        accCalculateInterestDetail.setInterestAmount(houseInterestAmount);
        accCalculateInterestDetail.setTransType(NumStrEnum.ONE.getNum());
        accCalculateInterestDetail.setRateNo(rateNo);
        accCalculateInterestDetail.setInterestYear(accCalculateInterestInfo.getInterestYear());
        accCalculateInterestDetail.setInterestDate(accCalculateInterestInfo.getInterestDate());
        return accCalculateInterestDetailMapper.insert(accCalculateInterestDetail);
    }

    /**
     * 修改结息表
     *
     * @param accCalculateInterestInfo
     * @param interestAmount
     * @return
     */
    private int updateAccCalculateInterestinfo(AccCalculateInterestInfo accCalculateInterestInfo, BigDecimal interestAmount) {
        accCalculateInterestInfo.setTotalInterest(interestAmount);
        accCalculateInterestInfo.setOperNo(ShiroUserUtil.getUserName());
        accCalculateInterestInfo.setOperTime(DateUtils.getNow());
        //是否结息中  1是  0否
        //accCalculateInterestInfo.setIsCalculation(NumStrEnum.ZERO.getNum());
        //是否预结息  1是  0否
        accCalculateInterestInfo.setIsAdvance(NumStrEnum.ONE.getNum());
        return accCalculateInterestInfoMapper.update(accCalculateInterestInfo);
    }

    /**
     * 检查利率日期区间是否完成
     *
     * @param rateInfoList
     * @return
     */
    private boolean checkRateDate(List<AccRateInfo> rateInfoList) {
        boolean flag = true;
        //检查是否存在
        if (null == rateInfoList || rateInfoList.isEmpty()) {
            flag = false;
        } else {
            //判断是否有空档日期
            for (int i = 0; i < rateInfoList.size() - 1; i++) {
                int dayNumber = DateFormatUtil.getDiscrepantDays(DateFormatUtil.getDateFormat(rateInfoList.get(i + 1).getStartDate(), "yyyy-MM-dd"), DateFormatUtil.getDateFormat(rateInfoList.get(i).getEndDate(), "yyyy-MM-dd"));
                if (dayNumber > 1) {
                    flag = false;
                }
            }
        }
        return flag;
    }

    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult advanceInterestFix(AccCalculateInterestInfo accCalculateInterestInfo) {
        currentProgressCount = 0;
        //当前结息日期
        String currentDate = accCalculateInterestInfo.getInterestYear() + "-" + accCalculateInterestInfo.getInterestDate();
        //查询最后一次已结息记录
        AccCalculateInterestInfo lastCalculationInfo = accCalculateInterestInfoMapper.getLastCalculationInfo();
        //上次结息日期 没有则赋值最小的缴存记账日期 表示系统第一次结息
        String lastDate = null != lastCalculationInfo ? lastCalculationInfo.getInterestYear() + "-" + lastCalculationInfo.getInterestDate() : getMinDepTallyDate(currentDate);
        Date currentDateFormat = DateFormatUtil.getDateFormat(currentDate, "yyyy-MM-dd");
        Date lastDateFormat = DateFormatUtil.getDateFormat(lastDate, "yyyy-MM-dd");
        //查询房屋绑定过的承办银行（1，2，3，... ...）
        String bankIdList = baseHouseInfoMapper.getBankIdListToInterest();
        //判断是否选择定期利率类型 ...
        String rateType = accCalculateInterestInfo.getRateType();
        if (StringUtils.isEmpty(rateType)) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "请先在利率设置中选择并确认定期利率类型！");
        }
        //根据结息类型和结息区间查询利率列表  最近结息时间>=利息开始时间  && 利息结束时间>=当前结息日期
        List<AccRateInfo> fixRateInfoList = accRateInfoMapper.getListByDateAndRateType(currentDate, lastDate, bankIdList, rateType);
        //查询获取利率表
        List<AccRateInfo> rateInfoList = accRateInfoMapper.getListByDateAndRateType(currentDate, lastDate, bankIdList, NumStrEnum.ONE.getNum());
        //检查是否所有银行都存在设置利率且日期是否连续
        String[] arrBankId = bankIdList.split(",");
        for (String sBandId : arrBankId) {
            //活期
            List<AccRateInfo> tmpRateInfoList = rateInfoList.stream().filter((AccRateInfo accRateinfo) -> accRateinfo.getBankId().equals(sBandId)).collect(Collectors.toList());
            BaseBankInfo bankInfo = baseBankInfoMapper.getInfo(sBandId);
            if (null == tmpRateInfoList || tmpRateInfoList.isEmpty()) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), bankInfo.getBankName() + "活期利率未配置利率或利率不完整！");
            }
            //检查利率日期是否完整
            if (!checkRateDate(tmpRateInfoList)) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), bankInfo.getBankName() + "活期利率利率日期不完整");
            }
            //定期
            tmpRateInfoList = fixRateInfoList.stream().filter((AccRateInfo accRateinfo) -> accRateinfo.getBankId().equals(sBandId)).collect(Collectors.toList());
            //检查利率日期是否完整
            if (!checkRateDate(tmpRateInfoList)) {
                String name = sysDicRateListMapper.getRateNameById(accCalculateInterestInfo.getRateType());
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), bankInfo.getBankName() + name + "未配置利率或利率日期不完整");
            }
        }
        //查询有当前资金余额的房屋的id、资金余额、利息、承办银行列表
        List<BaseHouseInfo> houseList = baseHouseInfoMapper.getHouseListToInterest(currentDate);
        if (null == houseList || houseList.isEmpty()) {
            int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, BigDecimal.ZERO);
            return CommonResult.ResponseResult(num);
        }
        //所有房间的总利息
        BigDecimal totalInterest = BigDecimal.ZERO;
        totalCount = houseList.size();
        for (BaseHouseInfo baseHouseInfo : houseList) {
            currentProgressCount++;
            sendWebSocket(totalCount, currentProgressCount, "正在计算");
            //单个房间的总利息
            BigDecimal houseTotalInterest;
            //获取当前银行利率列表
            List<AccRateInfo> currentRateInfoList = rateInfoList.stream().filter((AccRateInfo accRateinfo) -> accRateinfo.getBankId().equals(baseHouseInfo.getBankCode())).collect(Collectors.toList());
            List<AccRateInfo> currentFixRateInfoList = fixRateInfoList.stream().filter((AccRateInfo accRateinfo) -> accRateinfo.getBankId().equals(baseHouseInfo.getBankCode())).collect(Collectors.toList());
            String detailId = UUIDUtil.getUUID();
            BigDecimal houseTotalFixedInterest = getHouseTotalFixedInterest(currentFixRateInfoList, currentRateInfoList, lastDateFormat, currentDateFormat, baseHouseInfo, lastDate, currentDate, accCalculateInterestInfo.getRateNo(), detailId);
            houseTotalInterest = houseTotalFixedInterest;
            //加总利息
            totalInterest = totalInterest.add(houseTotalInterest);
            //保存结息详情表
            saveAccCalculateInterestDetail(baseHouseInfo, houseTotalInterest, accCalculateInterestInfo.getRateNo(), detailId, accCalculateInterestInfo);
        }
        //更新结息表状态
        int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, totalInterest);
        return CommonResult.ResponseResult(num);
    }

    /**
     * 活转定方式计息 ，即当前计息期间有业务发生的按活期否则按定期计算
     *
     * @param rateInfoList      活期利率列表
     * @param lastDateFormat    最后一次计息日期 Date
     * @param currentDateFormat 本次计息日期
     * @param baseHouseInfo     房屋信息
     * @param lastDate          最后一次计息日期  String
     * @param currentDate       本次计息日期
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public BigDecimal getHouseTotalFixedInterest(List<AccRateInfo> fixRateInfoList, List<AccRateInfo> rateInfoList, Date lastDateFormat, Date currentDateFormat, BaseHouseInfo baseHouseInfo, String lastDate, String currentDate, String rateNo, String detailId) {
        //单个房间的总利息
        BigDecimal houseTotalInterest = BigDecimal.ZERO;
        //查询房屋的记账记录,非结息记录   记账日期>=最近结息日期  &&  记账日期<当前日期结息
        List<AccCalculateInterestDetailLog> accCalculateInterestDetailLogList = accCalculateInterestDetailLogMapper.getLogListByHouseIdAndDateInterval(baseHouseInfo.getId(), lastDate, currentDate);
        //查询最后一次结息的信息
        AccTransactionLog lastInterestInfo = accTransactionLogMapper.getLastInterestInfoByHouseId(baseHouseInfo.getId());
        BigDecimal lastFundBal = null == lastInterestInfo || null == lastInterestInfo.getFundBal() ? BigDecimal.ZERO : lastInterestInfo.getFundBal();
        BigDecimal lastAccrBal = null == lastInterestInfo || null == lastInterestInfo.getAccrBal() ? BigDecimal.ZERO : lastInterestInfo.getAccrBal();
        //查询最近结息日期
        //查询时间段是否发生过使用、退款的交易
        List<AccCalculateInterestDetailLog> outList = accCalculateInterestDetailLogList.stream().filter(a -> "310".equals(a.getBusiType()) || "312".equals(a.getBusiType())).collect(Collectors.toList());
        //有  按活期计息
        if (null != outList && outList.size() > 0) {
            houseTotalInterest = getHouseTotalInterest(rateInfoList, currentDateFormat, baseHouseInfo, lastDate, currentDate, rateNo, detailId, BigDecimal.ZERO);
        } else {
            //无  查询时间段房屋的交存交易
            List<AccCalculateInterestDetailLog> inList = accCalculateInterestDetailLogList.stream().filter(a -> "311".equals(a.getBusiType())).collect(Collectors.toList());
            if (null != inList && inList.size() > 0) {
                //交叉活期息
                BigDecimal currentAmount = getHouseTotalInterest(rateInfoList, currentDateFormat, baseHouseInfo, lastDate, currentDate, rateNo, detailId, lastFundBal.add(lastAccrBal));
                //上次结息时的资金余额为定期本金定期计息
                //交叉定期息  有上次计息记录时计算定期   否则为首次计息，首次计息只计算活期
                BigDecimal fixedAmount = BigDecimal.ZERO;
                if (null != lastInterestInfo) {
                    fixedAmount = getFixedInterest(fixRateInfoList, lastDateFormat, currentDateFormat, lastDate, currentDate, rateNo, lastFundBal, lastAccrBal, accCalculateInterestDetailLogList.get(0).getTransactionLogId(), detailId);
                }
                houseTotalInterest = currentAmount.add(fixedAmount);
            } else {
                //无  上次结息时的资金余额为定期本金定期计息
                if (null != lastInterestInfo) {
                    houseTotalInterest = getFixedInterest(fixRateInfoList, lastDateFormat, currentDateFormat, lastDate, currentDate, rateNo, lastFundBal, lastAccrBal, accCalculateInterestDetailLogList.get(0).getTransactionLogId(), detailId);
                }
            }
        }
        return houseTotalInterest;
    }

    /**
     * 查询最近结息日期
     *
     * @param houseId
     * @return
     */
    private String getHouseLastInterestDate(String houseId) {
        AccCalculateInterestInfo lastCalculationInfo = accCalculateInterestInfoMapper.getLastCalculationInfo();
        String lastInterestDate = lastInterestDate = null == lastCalculationInfo ? null : lastCalculationInfo.getInterestYear() + "-" + lastCalculationInfo.getInterestDate();
        if (null == lastCalculationInfo) {

        }
        return lastInterestDate;
    }

    /**
     * 定期计算金额
     *
     * @return
     */
    private BigDecimal getFixedInterest(List<AccRateInfo> fixRateInfoList, Date lastDateFormat, Date currentDateFormat, String lastDate, String currentDate, String rateNo, BigDecimal fundBal, BigDecimal accrBal, String transactionLogId, String detailId) {
        //获取适用的利率
        List<AccRateInfo> minList = fixRateInfoList.stream().filter(rateInfo -> !DateFormatUtil.getDateFormat(rateInfo.getStartDate(), "yyyy-MM-dd").after(lastDateFormat)).collect(Collectors.toList());
        BigDecimal currentFixRate = minList.get(minList.size() - 1).getRate();
        //计息天数 当前结息日期 - 最后结息  全程按定期
        int dayNumber = DateFormatUtil.getDiscrepantDays(lastDateFormat, currentDateFormat);
        //计算 (本金+利息)*定期利率/36000*天数
        BigDecimal dFundBal = null != fundBal ? fundBal : BigDecimal.ZERO;
        BigDecimal dAccrBal = null != accrBal ? accrBal : BigDecimal.ZERO;
        BigDecimal tmpAmount = dFundBal.add(dAccrBal);
        //日lilv
        BigDecimal dRate = currentFixRate.divide(new BigDecimal(36000), 12, BigDecimal.ROUND_HALF_UP);//利率 / 100 /360
        BigDecimal interestAmount = tmpAmount.multiply(dRate).multiply(new BigDecimal(dayNumber));
        BigDecimal houseTotalInterest = interestAmount.setScale(4, BigDecimal.ROUND_DOWN);
        //保存记录
        AccCalculateInterestDetailLog accCalculateInterestDetailLog = new AccCalculateInterestDetailLog();
        accCalculateInterestDetailLog.setId(UUIDUtil.getUUID());
        accCalculateInterestDetailLog.setInterestAmount(houseTotalInterest);
        accCalculateInterestDetailLog.setDayNumber(dayNumber);
        accCalculateInterestDetailLog.setRateNo(rateNo);
        accCalculateInterestDetailLog.setRate(currentFixRate.toString());
        accCalculateInterestDetailLog.setInterestStartDate(lastDateFormat);
        accCalculateInterestDetailLog.setInterestEndDate(currentDateFormat);
        accCalculateInterestDetailLog.setFundBal(tmpAmount);
        accCalculateInterestDetailLog.setTransactionLogId(transactionLogId);
        accCalculateInterestDetailLog.setDetailId(detailId);
        accCalculateInterestDetailLogMapper.insert(accCalculateInterestDetailLog);
        return houseTotalInterest;
    }


    /**
     * 设定利息方式
     *
     * @param accCalculateInterestInfo
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult advanceInterestSetInterest(AccCalculateInterestInfo accCalculateInterestInfo) {
        currentProgressCount = 0;
        //判断是否设置分配金额
        BigDecimal interest = accCalculateInterestInfo.getInterest();
        if (null == interest) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "请先设置分配金额");
        }
        //当前结息日期
        String currentDate = accCalculateInterestInfo.getInterestYear() + "-" + accCalculateInterestInfo.getInterestDate();
        //获取分摊系数 分摊金额/sum(各业务金额*各业务到当前日期的时间间隔)
        BigDecimal disRatio = accTransactionLogMapper.getDistributionCoefficient(interest, currentDate);
        //获取每户应分摊的金额 分摊系数*每房间各业务金额*各业务到当前日期的时间间隔
        List<AccTransactionLog> accTransactionLogList = accTransactionLogMapper.getDistributionAmount(disRatio, currentDate);
        if (accTransactionLogList.isEmpty()) {
            int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, accCalculateInterestInfo.getDistributionAmount());
            return CommonResult.ResponseResult(num);
        }
        //获取所有房间加总的分摊金额
        BigDecimal houseTotalInterest = BigDecimal.ZERO;
        for (AccTransactionLog accTlog : accTransactionLogList) {
            houseTotalInterest = houseTotalInterest.add(accTlog.getDisAmount());
        }
        //计算欲分摊金额 与实际计算分摊金额的差
        BigDecimal diffAmount = accCalculateInterestInfo.getInterest().subtract(houseTotalInterest);
        //循环随机每户 加或减一分
        if (diffAmount.compareTo(BigDecimal.ZERO) > 0)  //还有没分摊的金额 遍历逐户加一分
        {
            while (diffAmount.compareTo(BigDecimal.ZERO) > 0) {
                for (int i = 0; i < accTransactionLogList.size(); i++) {
                    diffAmount = diffAmount.subtract(BigDecimal.valueOf(0.01));
                    BigDecimal tmpDisAmount = accTransactionLogList.get(i).getDisAmount();
                    accTransactionLogList.get(i).setDisAmount(tmpDisAmount.add(BigDecimal.valueOf(0.01)));
                    if (diffAmount.compareTo(BigDecimal.ZERO) == 0) {
                        break;
                    }
                }
            }
        }
        if (diffAmount.compareTo(BigDecimal.ZERO) < 0) //多分摊了金额 遍历逐户减一分
        {
            while (diffAmount.compareTo(BigDecimal.ZERO) < 0) {
                for (int i = 0; i < accTransactionLogList.size(); i++) {
                    diffAmount = diffAmount.add(BigDecimal.valueOf(0.01));
                    BigDecimal tmpDisAmount = accTransactionLogList.get(i).getDisAmount();
                    accTransactionLogList.get(i).setDisAmount(tmpDisAmount.subtract(BigDecimal.valueOf(0.01)));
                    if (diffAmount.compareTo(BigDecimal.ZERO) == 0) {
                        break;
                    }
                }
            }
        }
        totalCount = accTransactionLogList.size();
        //保存结息详情表及记录
        for (AccTransactionLog tmpAccTranLog : accTransactionLogList) {
            currentProgressCount++;
            String detailId = UUIDUtil.getUUID();
            sendWebSocket(totalCount, currentProgressCount, "正在结息..");
            AccCalculateInterestDetailLog accCalculateInterestDetailLog = new AccCalculateInterestDetailLog();
            accCalculateInterestDetailLog.setId(UUIDUtil.getUUID());
            accCalculateInterestDetailLog.setInterestAmount(tmpAccTranLog.getDisAmount());
            accCalculateInterestDetailLog.setRateNo(accCalculateInterestInfo.getRateNo());
            accCalculateInterestDetailLog.setDayNumber(tmpAccTranLog.getDaySum());
            accCalculateInterestDetailLog.setInterestStartDate((DateFormatUtil.getDateFormat(tmpAccTranLog.getTallyDate(), "yyyy-MM-dd")));
            accCalculateInterestDetailLog.setInterestEndDate(DateFormatUtil.getDateFormat(currentDate, "yyyy-MM-dd"));
            accCalculateInterestDetailLog.setDetailId(detailId);
            accCalculateInterestDetailLogMapper.insert(accCalculateInterestDetailLog);
            AccCalculateInterestDetail accCalculateInterestDetail = new AccCalculateInterestDetail();
            accCalculateInterestDetail.setId(detailId);
            accCalculateInterestDetail.setBankId(tmpAccTranLog.getBankId());
            accCalculateInterestDetail.setHouseId(tmpAccTranLog.getHouseId());
            accCalculateInterestDetail.setInterestAmount(tmpAccTranLog.getDisAmount());
            accCalculateInterestDetail.setTransType(NumStrEnum.ONE.getNum());
            accCalculateInterestDetail.setRateNo(accCalculateInterestInfo.getRateNo());
            accCalculateInterestDetailMapper.insert(accCalculateInterestDetail);
        }
        //更新结息表状态
        int num = updateAccCalculateInterestinfo(accCalculateInterestInfo, accCalculateInterestInfo.getDistributionAmount());
        return CommonResult.ResponseResult(num);
    }

    /**
     * sendWebSocket 消息推送
     *
     * @param totalCount           总条数
     * @param currentProgressCount 当前条数
     * @param progress             进程（计算/记账）
     */
    private void sendWebSocket(int totalCount, int currentProgressCount, String progress) {
        JSONObject s = new JSONObject();
        s.put("progress", progress);
        s.put("totalCount", totalCount);
        try {
            s.put("currentProgressCount", currentProgressCount);
            WebSocketServer.sendInfo(String.valueOf(s), null);
            if (totalCount == currentProgressCount) {
                return;
            }
        } catch (Exception e) {
            log.error("错误信息:()", e.getMessage(), e);
        }
    }

    /**
     * 查询最小的缴存记账日期   新系统第一次结息用到
     *
     * @return
     */
    private String getMinDepTallyDate(String interestDate) {
        String date = accCalculateInterestInfoMapper.getMinDepTallyDate(interestDate);
        return null != date ? date : interestDate;
    }

    /**
     * 检查承办银行是否结算
     *
     * @return
     */
    private Map<String, String> checkContractorBankIsSettlement(String interestDate) {
        Map<String, String> map = new HashMap<>();
        List<BaseContractorBankInfo> list = baseContractorBankInfoMapper.getOpenList();
        for (BaseContractorBankInfo b : list) {
            Date date = DateFormatUtil.getDateFormat(interestDate, "yyyy-MM-dd");
            if (null == b.getSettlementTime() || date.after(DateFormatUtil.getDateFormat(b.getSettlementTime(), "yyyy-MM-dd"))) {
                BaseBankInfo info = baseBankInfoMapper.getInfo(b.getBankId());
                map.put("code", NumStrEnum.ZERO.getNum());
                map.put("msg", info.getBankName() + "未结算！请先结算然后结息！");
            }
        }
        return map;
    }

    /**
     * 检查结息信息状态
     *
     * @return
     */
    @Override
    public Map<String, String> checkCalculate(AccCalculateInterestInfo accCalculateInterestInfo) {
        Map<String, String> map = new HashMap<>();
        if (null != accCalculateInterestInfo) {
            if (NumStrEnum.ONE.getNum().equals(accCalculateInterestInfo.getIsCalculation())) {
                map.put("code", NumStrEnum.ZERO.getNum());
                map.put("msg", "正在结息中，请耐心等待！");
            }
            if (NumStrEnum.ONE.getNum().equals(accCalculateInterestInfo.getAccState())) {
                map.put("code", NumStrEnum.ZERO.getNum());
                map.put("msg", "已记账并写入财务，无法重复结息！");
            }
        }
        return map;
    }

    @Override
    @Transactional
    public int sendFinance(String rateNo) {
        int num = 1;
        String amount = accCalculateInterestInfoMapper.getSumPayAmountByRateNo(rateNo);
        List<Map<String, String>> financeList = getFinanceList(rateNo, amount);
        String sys = sysCoreParamMapper.getParamValueByCode("59");
        if (null == sys) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), "请去参数设计是否调用财务接口");
        }
        if (sys.equals(NumStrEnum.ONE.getNum())) {
            String res = connect(financeList);
            if (null != res) {
                num = saveAccBusiVouchLink(rateNo, res, amount);
            }
        }
        return num;
    }


    /**
     * 财务list
     *
     * @param rateNo
     * @return
     */
    private List<Map<String, String>> getFinanceList(String rateNo, String amount) {
        List<Map<String, String>> list = new ArrayList<>();
        int inid = 1;
        Map<String, String> map = putFinanceCommonMap();
        Map<String, String> firstMap = putFinanceFirstMap(map, inid, amount);
        List<Map<String, String>> buildCalculateList = accCalculateInterestInfoMapper.getBuildCalculateListByRateNo(rateNo);
        BigDecimal bigDecimal = BigDecimal.ZERO;
        for (Map<String, String> m : buildCalculateList) {
            String payAmount = null == m.get("payAmount") ? NumStrEnum.ZERO.getNum() : m.get("payAmount");
            bigDecimal = bigDecimal.add(new BigDecimal(payAmount));
        }
        firstMap.put("amount", bigDecimal + "");
        list.add(firstMap);
        for (Map<String, String> m : buildCalculateList) {
            map = putFinanceCommonMap();
            inid = inid + 1;
            Map<String, String> buildMap = putFinanceBuildMap(map, inid, m.get("payAmount"), m.get("financeCode"));
            list.add(buildMap);
        }
        //汇总信息
        return list;
    }

    /**
     * 财务接口第一个map,结息科目
     *
     * @return
     */
    private Map<String, String> putFinanceFirstMap(Map<String, String> map, int inid, String amount) {
        map.put("iperiod", DateUtils.getMmNow());
        map.put("inid", String.valueOf(inid));
        map.put("ccode", getInterestRateCode());
        map.put("amount", String.valueOf(amount));
        return map;
    }

    /**
     * 财务接口第一个map,结息科目
     *
     * @return
     */
    private Map<String, String> putFinanceBuildMap(Map<String, String> map, int inid, String amount, String ccode) {
        map.put("iperiod", DateUtils.getMmNow());
        map.put("inid", String.valueOf(inid));
        map.put("ccode", ccode);
        map.put("amount", amount);
        return map;
    }

    /**
     * 给财务map赋通用信息
     *
     * @return
     */
    private Map<String, String> putFinanceCommonMap() {
        Map<String, String> map = new HashMap<>();
        map.put("baseName", getSqlName());
        map.put("iperiod", DateUtils.getMmNow());
        map.put("csign", "息");
        map.put("isignseq", NumStrEnum.SEVEN.getNum());
        map.put("billDate", DateUtils.getNow());
        map.put("cdigest", "维修资金结息");
        return map;
    }

    /**
     * 结息数据名
     *
     * @return
     */
    private String getSqlName() {
        String mySqlName = sysCoreParamMapper.getParamValueByCode("57");
        String year = DateUtils.getYYYYNow();
        //之前日期
        String oldYear = mySqlName.substring(11, 15);
        return mySqlName.replace(oldYear, year);
    }

    /**
     * 结息代码
     *
     * @return
     */
    private String getInterestRateCode() {
        return sysCoreParamMapper.getParamValueByCode("60");
    }

    /**
     * 财务接口
     */
    public String connect(List<Map<String, String>> list) {
        String res = null;
        CloseableHttpClient client = HttpClients.createDefault();
        String url = "http://192.168.31.101:8091/AccVouch/writeAccVouch";
        HttpPost post = new HttpPost(url);
        net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();
        log.info("上送参数：" + list);
        jsonObject.accumulate("accVouchs", list);
        post.setHeader("Content-Type", "application/json;charset=utf-8");
        post.addHeader("Authorization", "Basic YWRtaW46");
        StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8");
        post.setEntity(entity);
        CloseableHttpResponse response = null;
        try {
            response = client.execute(post);
            log.info("原始相应:" + response);
            res = EntityUtils.toString(response.getEntity());
            log.info("原始body:" + res);
        } catch (Exception e) {
            log.error("错误信息:()", e.getMessage(), e);
        } finally {
            try {
                if (client != null) {
                    client.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error("IOException错误信息:()", e.getMessage(), e);
            }

        }
        return res;
    }

    private int saveAccBusiVouchLink(String rateNo, String res, String amount) {
        AccBusiVouchLink vouchLink = new AccBusiVouchLink();
        AccCalculateInterestInfo info = accCalculateInterestInfoMapper.getInfoByRateNo(rateNo);
        vouchLink.setBusiNo(rateNo);
        vouchLink.setInoId(res);
        vouchLink.setIsignseq(7);
        vouchLink.setCreater(ShiroUserUtil.getUserName());
        vouchLink.setPayAmount(new BigDecimal(amount));
        vouchLink.setCcode(getInterestRateCode());
        vouchLink.setAccountPeriod(info.getInterestYear() + "-" + StringUtils.substring(info.getInterestDate(), 0, 2));
        return accBusiVouchLinkMapper.insert(vouchLink);
    }


}
